package dao

import (
	"context"
	"database/sql"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"time"
)

var (
	ErrUserDuplicateEmail = errors.New("邮件冲突")
	ErrRecordNotFound     = gorm.ErrRecordNotFound
)

type UserDAO interface {
	Insert(ctx context.Context, u User) error
	FindByEmail(ctx context.Context, email string) (User, error)
	FindById(ctx context.Context, userId int64) (User, error)
	FindByPhone(ctx context.Context, phone string) (User, error)
	Update(ctx context.Context, u User) error
	FindByWechat(ctx *gin.Context, openId string) (User, error)
}

type GORMUserDAO struct {
	db *gorm.DB
}

func NewUserDao(db *gorm.DB) UserDAO {
	return &GORMUserDAO{
		db: db,
	}
}

func (ud *GORMUserDAO) Insert(ctx context.Context, u User) error {
	now := time.Now().UnixMilli()
	u.Ctime = now
	u.Utime = now
	err := ud.db.WithContext(ctx).Create(&u).Error
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		//邮件冲突
		const uniqueIndexErrno uint16 = 1062
		if mysqlErr.Number == uniqueIndexErrno {
			return ErrUserDuplicateEmail
		}
	}

	return err
}
func (ud *GORMUserDAO) FindByEmail(ctx context.Context, email string) (User, error) {
	var u User
	err := ud.db.WithContext(ctx).First(&u, "email = ?", email).Error
	if err == gorm.ErrRecordNotFound {
		//记录不存在
		return User{}, ErrRecordNotFound
	}
	return u, err
}

func (ud *GORMUserDAO) FindById(ctx context.Context, userId int64) (User, error) {
	var u User
	err := ud.db.WithContext(ctx).Model(&User{}).First(&u, "id = ?", userId).Error
	if err == gorm.ErrRecordNotFound {
		//记录不存在
		return User{}, ErrRecordNotFound
	}
	return u, err
}

func (ud *GORMUserDAO) FindByPhone(ctx context.Context, phone string) (User, error) {
	var u User
	err := ud.db.WithContext(ctx).First(&u, "phone = ?", phone).Error
	if err == gorm.ErrRecordNotFound {
		//记录不存在
		return User{}, ErrRecordNotFound
	}
	return u, err
}

func (ud *GORMUserDAO) FindByWechat(ctx *gin.Context, openId string) (User, error) {
	var u User
	err := ud.db.WithContext(ctx).First(&u, "wechat_open_id = ?", openId).Error
	if err == gorm.ErrRecordNotFound {
		//记录不存在
		return User{}, ErrRecordNotFound
	}
	return u, err
}

func (ud *GORMUserDAO) Update(ctx context.Context, u User) error {
	now := time.Now().UnixMilli()
	u.Utime = now
	return ud.db.Model(&u).Updates(u).Error
}

type User struct {
	Id       int64  `gorm:"primaryKey,autoIncrement"`
	Email    string `gorm:"unique"`
	Password string
	Phone    sql.NullString `gorm:"unique"`

	WechatOpenId  sql.NullString `gorm:"unique"`
	WechatUnionId sql.NullString

	Nickname sql.NullString `gorm:"size:128"`
	Birthday sql.NullInt64
	AboutMe  sql.NullString `gorm:"size:1024"`
	//创建时间
	Ctime int64
	//修改时间
	Utime int64
}
